/*
 * File:   main.cpp
 * Author: Kreyl
 * Project: Armlet2South
 *
 * Created on Feb 05, 2013, 20:27
 */

#include "led.h"
#include "kl_lib_f100.h"
#include "ch.h"
#include "hal.h"


#define MINUTE  5

// Internal
static inline void Init();
uint32_t Time, AlarmTime;
bool Bzzz, configured;

int main(void) {
    configured = false;
    // ==== Init clock system ====
    Clk.SetupBusDividers(ahbDiv16 , apbDiv1, apbDiv1);
    Clk.UpdateFreqValues();
    // ==== Init OS ====
    halInit();
    chSysInit();
    // ==== Init Hard & Soft ====
    Init();

    nvicEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(IRQ_PRIO_MEDIUM));
    nvicEnableVector(RTC_Alarm_IRQn, CORTEX_PRIORITY_MASK(IRQ_PRIO_MEDIUM));

    PinSetupOut(GPIOB, 6, omPushPull, ps50MHz);
    PinClear(GPIOB, 6);

    Time = MINUTE * 60;
    AlarmTime = 0;
    Bzzz = true;

    RCC->AHBENR |= RCC_APB1ENR_PWREN;
    RCC->AHBENR |= RCC_APB1ENR_BKPEN;   // Enable Backup clocks
    PWR->CR |= PWR_CR_DBP;              // Enable access to Backup Registers and RTC

    RCC->CSR |= RCC_CSR_LSION;
    while(!(RCC->CSR & RCC_CSR_LSIRDY));
    RCC->BDCR |= RCC_BDCR_RTCSEL_LSI;   // Used LSI as RTC clock
    RCC->BDCR |= RCC_BDCR_RTCEN;        // Enable RTC

//    RTC->CRL &= ~RTC_CRL_RSF;          // RTC Operation OFF
    while(!(RTC->CRL & RTC_CRL_RTOFF));
    RTC->CRL |= RTC_CRL_CNF;           // Enter Configuration mode
    while(!(RTC->CRL & RTC_CRL_RTOFF));
    RTC->CRH |= RTC_CRH_ALRIE | RTC_CRH_SECIE;          // Alarm Interrupt Enable
    RTC->PRLH = (39000 & (uint32_t)0x000F0000) >> 16;
    /* Set RTC PRESCALER LSB word */
    RTC->PRLL = (39000 & (uint32_t)0x0000FFFF);
    while(!(RTC->CRL & RTC_CRL_RTOFF));
    RTC->CNTH = 0;
    RTC->CNTL = 0;
    RTC->ALRH = (Time & (uint32_t)0x000F0000) >> 16;
    RTC->ALRL = (Time & (uint32_t)0x0000FFFF);

    while(!(RTC->CRL & RTC_CRL_RTOFF));
    RTC->CRL &= ~RTC_CRL_CNF;           // Exit from Configuration mode
    Uart.Printf("RTC init\r");
    configured = true;

    while(TRUE) {
        if(!configured) chThdSleepMilliseconds(999);
        else {
            if(Bzzz) {
                Uart.Printf("Bzz!\r");
                PinSet(GPIOB, 6);
                chThdSleepMilliseconds(100);
                PinClear(GPIOB, 6);
                Bzzz = false;
            }
            // Enter standby mode
            chThdSleepMilliseconds(999);
            SCB->SCR |= SCB_SCR_SLEEPDEEP;
            PWR->CR = PWR_CR_PDDS;
            PWR->CR |= PWR_CR_CWUF;
            __WFI();
        }
//        Uart.Printf("%u\r", ((RTC->CNTH << 16)|(RTC->CNTL)) );
    }
}


void Init() {
    JtagDisable();
    Uart.Init(9600);

	if(!(PWR->CSR & PWR_CSR_WUF)) Uart.Printf("\rDaisyChain AHB=%u; APB1=%u; APB2=%u\r", Clk.AHBFreqHz, Clk.APB1FreqHz, Clk.APB2FreqHz);
	else Uart.Printf("Wakeup\r");
}

extern "C" {
CH_IRQ_HANDLER(RTC_IRQHandler) {
    CH_IRQ_PROLOGUE();
    chSysLockFromIsr();
    if(RTC->CRL & RTC_CRL_SECF) {
//        Uart.Printf("i %u\r", ((uint32_t)(RTC->CNTH << 16)|(RTC->CNTL)) );
        RTC->CRL &= ~RTC_CRL_SECF;
    }
    if(RTC->CRL & RTC_CRL_ALRF) {
        Bzzz = true;
        Uart.Printf("irq %u\r", ((uint32_t)(RTC->CNTH << 16)|(RTC->CNTL)) );
        RTC->CRL &= ~RTC_CRL_ALRF;
        while(!(RTC->CRL & RTC_CRL_RTOFF));
        RTC->CRL |= RTC_CRL_CNF;
        AlarmTime = ((uint32_t)(RTC->CNTH << 16)|(RTC->CNTL)) + Time;
        RTC->ALRH = (AlarmTime & (uint32_t)0x000F0000) >> 16;
        RTC->ALRL = (AlarmTime & (uint32_t)0x0000FFFF);
        while(!(RTC->CRL & RTC_CRL_RTOFF));
        RTC->CRL &= ~RTC_CRL_CNF;
    }
    RTC->CRL &= ~0x07;
    chSysUnlockFromIsr();
    CH_IRQ_EPILOGUE();
}
CH_IRQ_HANDLER(RTC_Alarm_IRQHandler) {
    CH_IRQ_PROLOGUE();
    chSysLockFromIsr();
    Uart.Printf("Alarm\r");
    chSysUnlockFromIsr();
    CH_IRQ_EPILOGUE();
}

}
